{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "065129d7-f1a6-4392-8d7b-057c7e142643",
   "metadata": {},
   "source": [
    "## RLVR Example - Finetuning with Sagemaker\n",
    "\n",
    "This notebook demonstrates basic user flow for RLVR Finetuning from a model available in Sagemaker Jumpstart.\n",
    "Information on available models on jumpstart: https://docs.aws.amazon.com/sagemaker/latest/dg/jumpstart-foundation-models-latest.html"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1de5d415-2823-4230-85a7-12cfe33f1425",
   "metadata": {},
   "source": [
    "### Setup and Configuration\n",
    "\n",
    "Initialize the environment by importing necessary libraries and configuring AWS credentials"
   ]
  },
  {
   "cell_type": "code",
   "id": "10c2ef37-2425-4676-bc80-6d278d4e609a",
   "metadata": {},
   "source": [
    "# Configure AWS credentials and region\n",
    "#! ada credentials update --provider=isengard --account=<> --role=Admin --profile=default --once\n",
    "#! aws configure set region us-west-2\n",
    "\n",
    "from sagemaker.train.rlvr_trainer import RLVRTrainer\n",
    "from sagemaker.train.configs import InputData\n",
    "from rich import print as rprint\n",
    "from rich.pretty import pprint\n",
    "from sagemaker.core.resources import ModelPackage\n",
    "from sagemaker.train.common import TrainingType\n",
    "\n",
    "\n",
    "import boto3\n",
    "import os\n",
    "from sagemaker.core.helper.session_helper import Session\n",
    "\n",
    "# For MLFlow native metrics in Trainer wait, run below line with approriate region\n",
    "os.environ[\"SAGEMAKER_MLFLOW_CUSTOM_ENDPOINT\"] = \"https://mlflow.sagemaker.us-west-2.app.aws\"\n",
    "\n"
   ],
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "markdown",
   "id": "4dcadc97-8693-4387-aea8-b17c61e1d27e",
   "metadata": {},
   "source": [
    "### Create RLVRTrainer\n",
    "**Required Parameters** \n",
    "\n",
    "* `model`: base_model id on Sagemaker Hubcontent that is available to finetune (or) ModelPackage artifacts\n",
    "\n",
    "**Optional Parameters**\n",
    "* `custom_reward_function`: Custom reward function/Evaluator ARN\n",
    "* `model_package_group_name`: ModelPackage group name or ModelPackageGroup\n",
    "* `mlflow_resource_arn`: MLFlow app ARN to track the training job\n",
    "* `mlflow_experiment_name`: MLFlow app experiment name(str)\n",
    "* `mlflow_run_name`: MLFlow app run name(str)\n",
    "* `training_dataset`: Training Dataset - either Dataset ARN or S3 Path of the dataset (Please note these are required for a training job to run, can be either provided via Trainer or .train())\n",
    "* `validation_dataset`: Validation Dataset - either Dataset ARN or S3 Path of the dataset\n",
    "* `s3_output_path`: S3 path for the trained model artifacts"
   ]
  },
  {
   "cell_type": "code",
   "id": "58a2ab71-214a-4491-bb0d-979ecf164186",
   "metadata": {},
   "source": [
    "# For fine-tuning (prod)\n",
    "rlvr_trainer = RLVRTrainer(\n",
    "    model=\"meta-textgeneration-llama-3-2-1b-instruct\", # Union[str, ModelPackage] \n",
    "    model_package_group_name=\"sdk-test-finetuned-models\", #\"test-finetuned-models\", # Make it Optional\n",
    "    #mlflow_resource_arn=\"arn:aws:sagemaker:us-west-2:<>:mlflow-tracking-server/mmlu-eval-experiment\",  # Optional[str] - MLflow app ARN (auto-resolved if not provided), can accept name and search in the account\n",
    "    mlflow_experiment_name=\"test-rlvr-finetuned-models-exp\", # Optional[str]\n",
    "    mlflow_run_name=\"test-rlvr-finetuned-models-run\", # Optional[str]\n",
    "    training_dataset=\"s3://mc-flows-sdk-testing/input_data/rlvr-rlaif-test-data/train_285.jsonl\",     #\"arn:aws:sagemaker:us-west-2:<>:hub-content/AIRegistry/DataSet/MarketingDemoDataset1/1.0.0\", #Optional[]\n",
    "    s3_output_path=\"s3://mc-flows-sdk-testing/output/\",\n",
    "    #sagemaker_session=sagemaker_session,\n",
    "    #role=\"arn:aws:iam::<>:role/service-role/AmazonSageMaker-ExecutionRole-20250731T162975\"\n",
    "    #role=\"arn:aws:iam::<>:role/Admin\",\n",
    "    accept_eula=True\n",
    ")"
   ],
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "markdown",
   "id": "71f00f76-77dc-44a8-a7ad-f322713d716f",
   "metadata": {},
   "source": [
    "### Discover and update Finetuning options\n",
    "\n",
    "Each of the technique and model has overridable hyperparameters that can be finetuned by the user."
   ]
  },
  {
   "cell_type": "code",
   "id": "60198ab4-e561-40e4-8f59-7d595f246a4e",
   "metadata": {
    "scrolled": true
   },
   "source": [
    "print(\"Default Finetuning Options:\")\n",
    "pprint(rlvr_trainer.hyperparameters.to_dict()) # rename as hyperparameters\n",
    "\n",
    "#set options\n",
    "rlvr_trainer.hyperparameters.get_info()\n",
    "\n"
   ],
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "markdown",
   "id": "b34b5f7a-624f-4dfb-9d36-787cd456cfd9",
   "metadata": {},
   "source": [
    "#### Start RLVR training\n"
   ]
  },
  {
   "cell_type": "code",
   "id": "1f3f65a7-8ba6-4aa1-b6ea-606ddb2068c0",
   "metadata": {},
   "source": [
    "training_job = rlvr_trainer.train(wait=True)"
   ],
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "code",
   "id": "a60f83f2-a247-4506-9827-9dc3a603f629",
   "metadata": {},
   "source": [
    "import re\n",
    "from sagemaker.core.utils.utils import Unassigned\n",
    "import json\n",
    "\n",
    "\n",
    "def pretty_print(obj):\n",
    "    def parse_unassigned(item):\n",
    "        if isinstance(item, Unassigned):\n",
    "            return None\n",
    "        if isinstance(item, dict):\n",
    "            return {k: parse_unassigned(v) for k, v in item.items() if parse_unassigned(v) is not None}\n",
    "        if isinstance(item, list):\n",
    "            return [parse_unassigned(x) for x in item if parse_unassigned(x) is not None]\n",
    "        if isinstance(item, str) and \"Unassigned object\" in item:\n",
    "            pairs = re.findall(r\"(\\w+)=([^<][^=]*?)(?=\\s+\\w+=|$)\", item)\n",
    "            result = {k: v.strip(\"'\\\"\") for k, v in pairs}\n",
    "            return result if result else None\n",
    "        return item\n",
    "\n",
    "    cleaned = parse_unassigned(obj.__dict__ if hasattr(obj, '__dict__') else obj)\n",
    "    print(json.dumps(cleaned, indent=2, default=str))\n",
    "\n",
    "# Usage\n",
    "pretty_print(training_job)"
   ],
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "code",
   "id": "fae88520-f1ac-4375-9b2d-b7d33b1241ab",
   "metadata": {},
   "source": [
    "training_job = rlvr_trainer.train(wait=True)"
   ],
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "markdown",
   "id": "918185b8-6e42-4288-8bb9-908aee6ed566",
   "metadata": {},
   "source": [
    "### View any Training job details\n",
    "\n",
    "We can get any training job details and its status with TrainingJob.get(...)"
   ]
  },
  {
   "cell_type": "code",
   "id": "7e9213d4-a08f-413a-9888-88decfcc13a4",
   "metadata": {
    "scrolled": true
   },
   "source": [
    "from sagemaker.core.resources import TrainingJob\n",
    "\n",
    "response = TrainingJob.get(training_job_name=\"meta-textgeneration-llama-3-2-3b-instruct-rlvr-20251123033517\")\n",
    "pretty_print(response)"
   ],
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "code",
   "id": "edf8cf45-742c-4e32-a41e-55ca65557d67",
   "metadata": {
    "scrolled": true
   },
   "source": [
    "training_job.refresh()\n",
    "pretty_print(training_job)"
   ],
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "markdown",
   "id": "1fee52be-8fee-4fc7-9d9e-57a06e14188e",
   "metadata": {},
   "source": [
    "### Test RLVR with Custom RewardFunction\n",
    "\n",
    "Here we are providing a user-defined reward function ARN"
   ]
  },
  {
   "cell_type": "code",
   "id": "f1d6931c-0935-4b2b-9aaf-7de0d0b836a7",
   "metadata": {},
   "source": [
    "\n",
    "# For fine-tuning \n",
    "rlvr_trainer = RLVRTrainer(\n",
    "    model=\"meta-textgeneration-llama-3-2-1b-instruct\", # Union[str, ModelPackage] \n",
    "    model_package_group_name=\"sdk-test-finetuned-models\", # Make it Optional\n",
    "    #mlflow_resource_arn=\"arn:aws:sagemaker:us-west-2:<>:mlflow-tracking-server/mmlu-eval-experiment\",  # Optional[str] - MLflow app ARN (auto-resolved if not provided), can accept name and search in the account\n",
    "    mlflow_experiment_name=\"test-rlvr-finetuned-models-exp\", # Optional[str]\n",
    "    mlflow_run_name=\"test-rlvr-finetuned-models-run\", # Optional[str]\n",
    "    training_dataset=\"s3://mc-flows-sdk-testing/input_data/rlvr-rlaif-test-data/train_285.jsonl\", #Optional[]\n",
    "    s3_output_path=\"s3://mc-flows-sdk-testing/output/\",\n",
    "    #sagemaker_session=sagemaker_session,\n",
    "    #role=\"arn:aws:iam::<>:role/service-role/AmazonSageMaker-ExecutionRole-20250731T162975\"\n",
    "    #role=\"arn:aws:iam::<>:role/Admin\",\n",
    "    custom_reward_function=\"arn:aws:sagemaker:us-west-2:<>:hub-content/sdktest/JsonDoc/rlvr-test-rf/0.0.1\",\n",
    "    accept_eula=True\n",
    "    \n",
    ")"
   ],
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "code",
   "id": "4f406ee1-79bc-4062-b164-b599f41f1508",
   "metadata": {},
   "source": [
    "training_job = rlvr_trainer.train(wait=True)"
   ],
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "code",
   "id": "8738ad78-677a-449c-8854-24da5db238b7",
   "metadata": {},
   "source": [
    "training_job = rlvr_trainer.train(wait=True)"
   ],
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "code",
   "id": "83e3fde5-2c4d-4669-b807-3fe142eabbc9",
   "metadata": {
    "scrolled": true
   },
   "source": [
    "#training_job.refresh()\n",
    "pretty_print(training_job)"
   ],
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "code",
   "id": "6dd03d80-b248-4c7c-b311-f0812652cba5",
   "metadata": {},
   "source": [
    "\n",
    "#meta-textgeneration-llama-3-2-1b-instruct-rlvr-20251113182932"
   ],
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "markdown",
   "id": "c1c3edcc-3f6c-4b8b-9546-ec8ed7d81a77",
   "metadata": {},
   "source": [
    "## Continued Finetuning (or) Finetuning on Model Artifacts"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f868baa8-eedb-4cf8-8b25-6a142164e073",
   "metadata": {},
   "source": [
    "#### Discover a ModelPackage and get its details"
   ]
  },
  {
   "cell_type": "code",
   "id": "10375308-eb3f-42bc-a59c-fe65d528fbbd",
   "metadata": {
    "scrolled": true
   },
   "source": [
    "from rich import print as rprint\n",
    "from rich.pretty import pprint\n",
    "from sagemaker.core.resources import ModelPackage, ModelPackageGroup\n",
    "\n",
    "#model_package_iter = ModelPackage.get_all(model_package_group_name=\"test-finetuned-models-gamma\")\n",
    "model_package = ModelPackage.get(model_package_name=\"arn:aws:sagemaker:us-west-2:<>:model-package/test-finetuned-models-gamma/61\")\n",
    "\n",
    "pretty_print(model_package)"
   ],
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "markdown",
   "id": "85b3ac89-226b-4ba8-992c-d9b9c2b63251",
   "metadata": {},
   "source": [
    "#### Create Trainer\n",
    "\n",
    "Trainer creation is same as above Finetuning Section except for `model`'s input is ModelPackage(previously trained artifacts)"
   ]
  },
  {
   "cell_type": "code",
   "id": "a9a19b3d-f463-4f27-b27d-427bc7742ea6",
   "metadata": {},
   "source": [
    "# For fine-tuning \n",
    "rlvr_trainer = RLVRTrainer(\n",
    "    model=model_package, # Union[str, ModelPackage] \n",
    "    training_type=TrainingType.LORA, \n",
    "    model_package_group_name=\"test-finetuned-models-gamma\", #\"test-finetuned-models\", # Make it Optional\n",
    "    mlflow_resource_arn=\"arn:aws:sagemaker:us-west-2:<>:mlflow-tracking-server/mmlu-eval-experiment\",  # Optional[str] - MLflow app ARN (auto-resolved if not provided), can accept name and search in the account\n",
    "    mlflow_experiment_name=\"test-rlvr-finetuned-models-exp\", # Optional[str]\n",
    "    mlflow_run_name=\"test-rlvr-finetuned-models-run\", # Optional[str]\n",
    "    training_dataset=\"arn:aws:sagemaker:us-west-2:<>:hub-content/AIRegistry/DataSet/rlvr-rlaif-test-dataset/0.0.2\",     #\"arn:aws:sagemaker:us-west-2:<>:hub-content/AIRegistry/DataSet/MarketingDemoDataset1/1.0.0\", #Optional[]\n",
    "    s3_output_path=\"s3://open-models-testing-pdx/output\",\n",
    "    sagemaker_session=sagemaker_session,\n",
    "    #role=\"arn:aws:iam::<>:role/service-role/AmazonSageMaker-ExecutionRole-20250731T162975\"\n",
    "    role=\"arn:aws:iam::<>:role/Admin\"\n",
    ")"
   ],
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "code",
   "id": "d8316a2e-90dd-4d12-a883-0acbfbfc833d",
   "metadata": {},
   "source": [
    "# For fine-tuning \n",
    "rlvr_trainer = RLVRTrainer(\n",
    "    model=\"arn:aws:sagemaker:us-west-2:<>:model-package/test-finetuned-models-gamma/61\", # Union[str, ModelPackage] \n",
    "    training_type=TrainingType.LORA, \n",
    "    model_package_group_name=\"test-finetuned-models-gamma\", #\"test-finetuned-models\", # Make it Optional\n",
    "    mlflow_resource_arn=\"arn:aws:sagemaker:us-west-2:<>:mlflow-tracking-server/mmlu-eval-experiment\",  # Optional[str] - MLflow app ARN (auto-resolved if not provided), can accept name and search in the account\n",
    "    mlflow_experiment_name=\"test-rlvr-finetuned-models-exp\", # Optional[str]\n",
    "    mlflow_run_name=\"test-rlvr-finetuned-models-run\", # Optional[str]\n",
    "    training_dataset=\"arn:aws:sagemaker:us-west-2:<>:hub-content/AIRegistry/DataSet/rlvr-rlaif-test-dataset/0.0.2\",     #\"arn:aws:sagemaker:us-west-2:<>:hub-content/AIRegistry/DataSet/MarketingDemoDataset1/1.0.0\", #Optional[]\n",
    "    s3_output_path=\"s3://open-models-testing-pdx/output\",\n",
    "    sagemaker_session=sagemaker_session,\n",
    "    #role=\"arn:aws:iam::<>:role/service-role/AmazonSageMaker-ExecutionRole-20250731T162975\"\n",
    "    role=\"arn:aws:iam::<>:role/Admin\"\n",
    ")"
   ],
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "markdown",
   "id": "feadfe2b-2f55-4d76-88d1-ad636ce24bc1",
   "metadata": {},
   "source": [
    "#### Start the Training"
   ]
  },
  {
   "cell_type": "code",
   "id": "dd3722c9-bddd-465b-ae56-ab1475f4f6fd",
   "metadata": {},
   "source": [
    "training_job = rlvr_trainer.train(\n",
    "    wait=True,\n",
    ")"
   ],
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "code",
   "id": "c6bd0ed2-5e8e-4f3b-b148-23840f7d3d75",
   "metadata": {},
   "source": "pretty_print(training_job)",
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "markdown",
   "id": "6f93c7ef-0622-4706-a5f3-c1581c6fa285",
   "metadata": {},
   "source": [
    "#### Nova RLVR job"
   ]
  },
  {
   "cell_type": "code",
   "id": "c7648ad2-0795-45ed-bfa1-5f039a132426",
   "metadata": {},
   "source": [
    "import os\n",
    "os.environ['SAGEMAKER_REGION'] = 'us-east-1'\n",
    "\n",
    "# For fine-tuning \n",
    "rlvr_trainer = RLVRTrainer(\n",
    "    model=\"nova-textgeneration-lite-v2\", # Union[str, ModelPackage] \n",
    "    model_package_group_name=\"sdk-test-finetuned-models\", #\"test-finetuned-models\", # Make it Optional\n",
    "    #mlflow_resource_arn=\"arn:aws:sagemaker:us-east-1:<>:mlflow-app/app-UNBKLOAX64PX\",  # Optional[str] - MLflow app ARN (auto-resolved if not provided), can accept name and search in the account\n",
    "    mlflow_experiment_name=\"test-nova-rlvr-finetuned-models-exp\", # Optional[str]\n",
    "    mlflow_run_name=\"test-nova-rlvr-finetuned-models-run\", # Optional[str]\n",
    "    training_dataset=\"s3://mc-flows-sdk-testing-us-east-1/input_data/rlvr-nova/grpo-64-sample.jsonl\",\n",
    "    validation_dataset=\"s3://mc-flows-sdk-testing-us-east-1/input_data/rlvr-nova/grpo-64-sample.jsonl\",\n",
    "    s3_output_path=\"s3://mc-flows-sdk-testing-us-east-1/output/\",\n",
    "    custom_reward_function=\"arn:aws:sagemaker:us-east-1:<>:hub-content/sdktest/JsonDoc/rlvr-nova-test-rf/0.0.1\",\n",
    "    accept_eula=True\n",
    ")\n"
   ],
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "code",
   "id": "6621a885-d929-4c4d-b622-459772b4eebf",
   "metadata": {},
   "source": [
    "rlvr_trainer.hyperparameters.to_dict()"
   ],
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "code",
   "id": "daa592d7-7053-4994-be34-07bc61fef921",
   "metadata": {},
   "source": [
    "rlvr_trainer.hyperparameters.data_s3_path = 's3://example-bucket'\n",
    "\n",
    "rlvr_trainer.hyperparameters.reward_lambda_arn = 'arn:aws:lambda:us-east-1:<>:function:rlvr-nova-reward-function'"
   ],
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "code",
   "id": "881ba1de-d7e4-4b82-ae8a-593306e56a74",
   "metadata": {},
   "source": [
    "rlvr_trainer.hyperparameters.to_dict()"
   ],
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "code",
   "id": "447051d4-2a4c-4db9-a71e-8face7e5d4c5",
   "metadata": {},
   "source": [
    "training_job = rlvr_trainer.train(wait=True)"
   ],
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "code",
   "id": "3a0b0746-27ac-4e7c-ba86-72dffd8f2715",
   "metadata": {},
   "source": [
    "training_job = rlvr_trainer.train(wait=False)"
   ],
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "markdown",
   "id": "a9a2d70f-4af7-4e4d-8305-db5463f97f34",
   "metadata": {},
   "source": [
    "#### Nova RLVR job (<>)"
   ]
  },
  {
   "cell_type": "code",
   "id": "7b10e842-6142-4a0a-83c7-55390fc4022c",
   "metadata": {},
   "source": [
    "import os\n",
    "os.environ['SAGEMAKER_REGION'] = 'us-east-1'\n",
    "\n",
    "# For fine-tuning \n",
    "rlvr_trainer = RLVRTrainer(\n",
    "    model=\"nova-textgeneration-lite-v2\", # Union[str, ModelPackage] \n",
    "    model_package_group_name=\"test-prod-iad-model-pkg-group\", #\"test-finetuned-models\", # Make it Optional\n",
    "    #mlflow_resource_arn=\"arn:aws:sagemaker:us-east-1:<>:mlflow-app/app-UNBKLOAX64PX\",  # Optional[str] - MLflow app ARN (auto-resolved if not provided), can accept name and search in the account\n",
    "    mlflow_experiment_name=\"test-nova-rlvr-finetuned-models-exp\", # Optional[str]\n",
    "    mlflow_run_name=\"test-nova-rlvr-finetuned-models-run\", # Optional[str]\n",
    "    training_dataset=\"s3://ease-integ-test-input-<>-us-east-1/converse-serverless-test-data/grpo-64-sample.jsonl\",\n",
    "    validation_dataset=\"s3://ease-integ-test-input-<>-us-east-1/converse-serverless-test-data/grpo-64-sample.jsonl\",\n",
    "    s3_output_path=\"s3://ease-integ-test-output-<>-us-east-1/model-customization-algo/\",\n",
    "    custom_reward_function=\"arn:aws:sagemaker:us-east-1:<>:hub-content/recipestest/JsonDoc/nova-prod-iad-test-evaluator-lambda-reward-function/0.0.1\",\n",
    "    accept_eula=True\n",
    ")\n"
   ],
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "code",
   "id": "bbfc5853-9381-4a9f-b16f-dcf5c59f5999",
   "metadata": {},
   "source": [
    "rlvr_trainer.hyperparameters.to_dict()"
   ],
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "code",
   "id": "4dbb19c3-5cd1-4b24-95a1-a5cfd93f4e18",
   "metadata": {},
   "source": [
    "rlvr_trainer.hyperparameters.data_s3_path = 's3://example-bucket'\n",
    "\n",
    "rlvr_trainer.hyperparameters.reward_lambda_arn = 'arn:aws:lambda:us-east-1:<>:function:rlvr-nova-reward-function'"
   ],
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "code",
   "id": "1a491813-bf80-4485-bd32-c473f94af266",
   "metadata": {},
   "source": [
    "rlvr_trainer.hyperparameters.to_dict()"
   ],
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "code",
   "id": "24f13939-746f-420c-97f1-ece2cb0a8190",
   "metadata": {},
   "source": [
    "training_job = rlvr_trainer.train(wait=True)"
   ],
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "code",
   "id": "ed22071f-2161-462d-b1ca-f701adfa6e07",
   "metadata": {},
   "source": [],
   "outputs": [],
   "execution_count": null
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.10"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
